package hkppay

import (
	"context"
	"errors"
	"fmt"
	"strconv"

	"gitee.com/liuxuezhan/ar-platform/pay-channel-packet/payClient/dto"
	"github.com/bytedance/sonic"
)

type Hkp struct {
}

func NewHkp() *Hkp {
	return &Hkp{}
}

type Resp struct {
	Success   bool   `json:"success"`
	ErrorCode string `json:"errorCode"`
	Message   string `json:"message"`
	Data      any    `json:"data"`
}

// Payin 代收下单
func (p *Hkp) Payin(ctx context.Context, req dto.PayRequestDto) (dto.PayResponseDto, error) {
	// 金额单位转为分
	amount, err := strconv.ParseFloat(req.Order.Amount, 64)
	if err != nil {
		return dto.PayResponseDto{}, err
	}
	amount = amount * 100
	// 请求第三方接口
	url := req.Channel.Url + "/api/open/merchant/trade/create"
	m := make(map[string]string)
	m["merchantId"] = req.Merchant.MerchantId
	m["merchantOrderNo"] = req.Order.OrderNumber
	m["payType"] = "PIX_QRCODE"
	m["currency"] = "BRL"
	m["amount"] = fmt.Sprintf("%.0f", amount)
	m["content"] = req.Order.OrderNumber
	m["clientIp"] = req.UserAccount.ClientIp
	m["callback"] = req.Channel.NotifyUrl
	// 签名
	sign, err := GenerateSignature(m, req.Channel.SecretKey)
	if err != nil {
		return dto.PayResponseDto{}, err
	}
	m["sign"] = sign
	output, err := SendRequest(ctx, url, m)
	// 处理返回结果
	var resp Resp
	if err = sonic.UnmarshalString(output, &resp); err != nil {
		return dto.PayResponseDto{}, err
	}
	if !resp.Success {
		return dto.PayResponseDto{}, errors.New(resp.ErrorCode)
	}
	return dto.PayResponseDto{
		OrderNumber:   req.Order.OrderNumber,
		ChannelNumber: resp.Data.(map[string]any)["orderNo"].(string),
		PayUrl:        resp.Data.(map[string]any)["payUrl"].(string),
	}, nil
}

// PayinNotify 代收回调
func (p *Hkp) PayinNotify(req dto.PayNotifyReqDto) (dto.PayNotifyRespDto, error) {
	m := make(map[string]any)
	if err := sonic.UnmarshalString(req.Body, &m); err != nil {
		return dto.PayNotifyRespDto{}, err
	}
	b := make(map[string]string)
	for k, v := range m {
		switch v.(type) {
		case string:
			b[k] = v.(string)
		case float64:
			b[k] = strconv.Itoa(int(v.(float64)))
		}
	}
	sign, err := GenerateSignature(b, req.Channel.SecretKey)
	if err != nil {
		return dto.PayNotifyRespDto{}, errors.New("Signature generation failed")
	}
	if v, ok := m["sign"]; !ok || v != sign {
		return dto.PayNotifyRespDto{}, errors.New("Signature verification failed")
	}
	return dto.PayNotifyRespDto{
		OrderNumber:   b["merchantOrderNo"],
		ChannelNumber: b["orderNo"],
		Status:        b["status"],
	}, nil
}

// Payout 代付下单
func (p *Hkp) Payout(ctx context.Context, req dto.WithdrawRequestDto) (dto.WithdrawResponseDto, error) {
	// 金额单位转为分
	amount, err := strconv.ParseFloat(req.Order.Amount, 64)
	if err != nil {
		return dto.WithdrawResponseDto{}, err
	}
	amount = amount * 100
	// 请求第三方接口
	url := req.Channel.Url + "/api/open/merchant/payment/create"
	m := make(map[string]string)
	m["merchantId"] = req.Merchant.MerchantId
	m["merchantOrderNo"] = req.Order.OrderNumber
	m["currency"] = "BRL"
	m["amount"] = fmt.Sprintf("%.0f", amount)
	m["callback"] = req.Channel.NotifyUrl
	m["accountNo"] = req.PixAccount.AccountNo
	m["accountName"] = req.PixAccount.AccountName
	switch req.PixAccount.AccountType {
	case "CPF":
		m["accountType"] = "PIX_CPF"
		m["accountNo"] = "CPF"
	case "EMAIL":
		m["accountType"] = "PIX_EMAIL"
	case "PHONE":
		m["accountType"] = "PIX_PHONE"
	case "CNPJ":
		m["accountType"] = "PIX_CNPJ"
	}
	// 签名
	sign, err := GenerateSignature(m, req.Channel.SecretKey)
	if err != nil {
		return dto.WithdrawResponseDto{}, err
	}
	m["sign"] = sign
	output, err := SendRequest(ctx, url, m)
	// 处理返回结果
	var resp Resp
	if err = sonic.UnmarshalString(output, &resp); err != nil {
		return dto.WithdrawResponseDto{}, err
	}
	if !resp.Success {
		return dto.WithdrawResponseDto{}, errors.New(resp.ErrorCode)
	}
	return dto.WithdrawResponseDto{
		WithdrawNumber: req.Order.OrderNumber,
		ChannelNumber:  resp.Data.(map[string]any)["orderNo"].(string),
	}, nil
}

func (p *Hkp) PayoutNotify(req dto.WithdrawNotifyReqDto) (dto.WithdrawNotifyRespDto, error) {
	m := make(map[string]any)
	if err := sonic.UnmarshalString(req.Body, &m); err != nil {
		return dto.WithdrawNotifyRespDto{}, err
	}
	b := make(map[string]string)
	for k, v := range m {
		switch v.(type) {
		case string:
			b[k] = v.(string)
		case float64:
			b[k] = strconv.Itoa(int(v.(float64)))
		}
	}
	sign, err := GenerateSignature(b, req.Channel.SecretKey)
	if err != nil {
		return dto.WithdrawNotifyRespDto{}, errors.New("Signature generation failed")
	}
	if v, ok := m["sign"]; !ok || v != sign {
		return dto.WithdrawNotifyRespDto{}, errors.New("Signature verification failed")
	}
	return dto.WithdrawNotifyRespDto{
		OrderNumber:   b["merchantOrderNo"],
		ChannelNumber: b["orderNo"],
		Status:        b["status"],
	}, nil
}
